package com.richrail.model.entities;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.richrail.Depot;
import com.richrail.state.DepotState;
import com.richrail.state.TrainState;
import com.richrail.state.WagonState;

// The separation between the depot and storage has been made because
// we do not want to make the trains and wagons publicly accessible to the GUI.
public class DepotStorage
{
	private Depot depot;
	
	private Map<String, Train> trains = new LinkedHashMap<String, Train>();
	
	private Map<String, Wagon> wagons = new LinkedHashMap<String, Wagon>();
	
	public DepotStorage(Depot depot)
	{
		this.depot = depot;
	}
	
	public boolean addTrain(Train train)
	{
		if (trains.containsKey(train.getName()))
		{
			return false;
		}
		
		trains.put(train.getName(), train);
		depot.notifyObservers();
		
		return true;
	}
	
	public boolean removeTrain(String trainName)
	{
		Train train = trains.get(trainName);
		return train != null ? removeTrain(train) : false;
	}
	
	public boolean removeTrain(Train train)
	{
		if (trains.remove(train.getName()) != null)
		{
			train.clearWagons();
			depot.notifyObservers();
			
			return true;
		}
		
		return false;
	}
	
	public boolean addWagon(Wagon wagon)
	{
		if (wagons.containsKey(wagon.getName()))
		{
			return false;
		}
		
		wagons.put(wagon.getName(), wagon);
		depot.notifyObservers();
		
		return true;
	}

	public boolean removeWagon(String wagonName)
	{
		Wagon wagon = wagons.get(wagonName);
		return wagon != null ? removeWagon(wagon) : false;
	}
	
	public boolean removeWagon(Wagon wagon)
	{
		if (wagons.remove(wagon.getName()) != null)
		{
			Train train = wagon.decoupleFromTrain();
			
			if (train != null)
			{
				train.removeWagon(wagon);
			}
			
			depot.notifyObservers();
			
			return true;
		}
		
		return false;
	}
	
	public boolean addWagonToTrain(String wagonName, String trainName)
	{
		if (!wagons.containsKey(wagonName) || !trains.containsKey(trainName))
		{
			return false;
		}
		
		Wagon wagon = wagons.get(wagonName);
		Train train = trains.get(trainName);
		boolean success = wagon.coupleToTrain(train);
		
		if (success)
		{
			train.addWagon(wagon);
			depot.notifyObservers();
		}
		
		return success;
	}

	public boolean removeWagonFromTrain(String wagonName, String trainName)
	{
		if (!wagons.containsKey(wagonName) || !trains.containsKey(trainName))
		{
			return false;
		}
		
		Wagon wagon = wagons.get(wagonName);
		Train train = wagon.decoupleFromTrain(trains.get(trainName));
		
		if (train != null)
		{
			train.removeWagon(wagon);
			depot.notifyObservers();
		}
		
		return train != null;
	}
	
	public int getTrainSeatCount(String trainName)
	{
		Train train = trains.get(trainName);
		return train != null ? train.getSeatCount() : -1;
	}

	public int getWagonSeatCount(String wagonName)
	{
		Wagon wagon = wagons.get(wagonName);
		return wagon != null ? wagon.getSeatCount() : -1;
	}
	
	public DepotState getState()
	{
		List<TrainState> trainStates = new ArrayList<TrainState>();
		
		for (Train t: trains.values())
		{
			trainStates.add(t.getState());
		}
		
		List<WagonState> wagonStates = new ArrayList<WagonState>();
		
		for (Wagon w: wagons.values())
		{
			wagonStates.add(w.getState());
		}
		
		return new DepotState(trainStates, wagonStates);
	}
}
